package com.wish233.register.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.wish233.config.RegistryConfig;
import com.wish233.model.register.ServiceMetaInfo;
import com.wish233.register.Registry;
import com.wish233.utils.HeartBeatUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author WHH
 * nacos配置中心
 */
@Slf4j
public class NacosRegistry implements Registry {

    private final Map<String, EventListener> listenerMap = new ConcurrentHashMap<>();
    private NamingService namingService;
    private RegistryServiceCache cache;

    @Override
    public void init(RegistryConfig registryConfig) {
        try {
            namingService = NamingFactory.createNamingService(registryConfig.getAddress());
            heartBeat();
            Runtime.getRuntime().addShutdownHook(new Thread(this::destroy));
            cache = RegistryServiceCache.getCache();
        } catch (NacosException e) {
            throw new RuntimeException("初始化Nacos注册中心失败", e);
        }
    }

    @Override
    public void register(ServiceMetaInfo serviceMetaInfo) throws Exception {
        String serviceName = serviceMetaInfo.getServiceName();
        String groupName = getGroupName(serviceMetaInfo);
        Instance instance = new Instance();
        instance.setIp(serviceMetaInfo.getServiceHost());
        instance.setPort(serviceMetaInfo.getServicePort());
        instance.setServiceName(serviceName);
        instance.setClusterName(groupName);
        instance.setMetadata(convertMetaToMap(serviceMetaInfo));
        // 注册实例
        namingService.registerInstance(serviceName, groupName, instance);
        // 添加心跳节点
        HeartBeatUtils.addNode(serviceMetaInfo.getServiceNodeKey());
    }

    @Override
    public void unRegister(ServiceMetaInfo serviceMetaInfo) {
        try {
            String serviceName = serviceMetaInfo.getServiceName();
            String groupName = getGroupName(serviceMetaInfo);
            namingService.deregisterInstance(serviceName, groupName,
                    serviceMetaInfo.getServiceHost(), serviceMetaInfo.getServicePort());
            HeartBeatUtils.removeNode(serviceMetaInfo.getServiceNodeKey());
        } catch (NacosException e) {
            log.error("服务注销失败", e);
        }
    }

    @Override
    public List<ServiceMetaInfo> serviceDiscovery(String serviceKey) {
        // 读缓存
        List<ServiceMetaInfo> serviceMetaInfos = cache.readCache(serviceKey);
        if (CollectionUtil.isNotEmpty(serviceMetaInfos)) {
            return serviceMetaInfos;
        }
        // 解析服务名和组名
        String[] parts = serviceKey.split(":");
        String serviceName = parts[0];
        String groupName = parts.length > 1 ? parts[1] : "DEFAULT_GROUP";
        try {
            // 获取服务实例
            List<Instance> instances = namingService.getAllInstances(serviceName, groupName);
            // 转换为ServiceMetaInfo列表
            List<ServiceMetaInfo> metaInfoList = instances.stream()
                    .map(this::convertInstanceToMeta)
                    .collect(Collectors.toList());
            // 监听服务变化
            watch(serviceKey);
            // 写缓存
            cache.writeCache(serviceKey, metaInfoList);
            return metaInfoList;
        } catch (NacosException e) {
            throw new RuntimeException("服务发现失败", e);
        }
    }

    @Override
    public void heartBeat() {
        // Nacos客户端会自动维持心跳，这里可以简化实现
        HeartBeatUtils.doHeartBeat(key -> {
            try {
                // 解析服务信息
                String[] parts = key.split(":");
                if (parts.length < 4) {
                    return;
                }
                String serviceName = parts[0] + ":" + parts[1];
                String groupName = parts.length > 4 ? parts[4] : "DEFAULT_GROUP";
                // 检查实例是否存在
                boolean healthy = namingService.getAllInstances(serviceName, groupName).stream()
                        .anyMatch(instance ->
                                instance.getIp().equals(parts[2]) &&
                                        instance.getPort() == Integer.parseInt(parts[3]));
                if (!healthy) {
                    // 重新注册
                    ServiceMetaInfo metaInfo = new ServiceMetaInfo();
                    metaInfo.setServiceName(parts[0]);
                    metaInfo.setServiceVersion(parts[1]);
                    metaInfo.setServiceHost(parts[2]);
                    metaInfo.setServicePort(Integer.parseInt(parts[3]));
                    register(metaInfo);
                }
            } catch (Exception e) {
                log.error("心跳检测失败", e);
            }
        });
    }

    @Override
    public void destroy() {
        Set<String> set = HeartBeatUtils.getSet();
        // 下线所有节点
        for (String key : set) {
            try {
                String[] parts = key.split(":");
                if (parts.length < 4) continue;
                ServiceMetaInfo metaInfo = new ServiceMetaInfo();
                metaInfo.setServiceName(parts[0]);
                metaInfo.setServiceVersion(parts[1]);
                metaInfo.setServiceHost(parts[2]);
                metaInfo.setServicePort(Integer.parseInt(parts[3]));
                unRegister(metaInfo);
            } catch (Exception e) {
                log.error("节点下线失败: {}", key, e);
            }
        }
        log.info("Nacos注册中心关闭");
    }

    @Override
    public void watch(String serviceKey) {
        if (listenerMap.containsKey(serviceKey)) {
            return;
        }
        String[] parts = serviceKey.split(":");
        String serviceName = parts[0];
        String groupName = parts.length > 1 ? parts[1] : "DEFAULT_GROUP";
        try {
            EventListener listener = event -> {
                if (event instanceof NamingEvent) {
                    NamingEvent namingEvent = (NamingEvent) event;
                    // 清理缓存
                    cache.clearCache(serviceKey);
                    // 重新获取服务列表
                    serviceDiscovery(serviceKey);
                }
            };
            namingService.subscribe(serviceName, groupName, listener);
            listenerMap.put(serviceKey, listener);
        } catch (NacosException e) {
            throw new RuntimeException("监听服务变化失败", e);
        }
    }


    private String getGroupName(ServiceMetaInfo metaInfo) {
        //暂时不支持多个group
        return "DEFAULT_GROUP";
    }

    private Map<String, String> convertMetaToMap(ServiceMetaInfo metaInfo) {
        Map<String, String> metadata = new HashMap<>();
        metadata.put("serviceName", metaInfo.getServiceName());
        metadata.put("serviceVersion", metaInfo.getServiceVersion());
        metadata.put("serviceHost", metaInfo.getServiceHost());
        metadata.put("servicePort", String.valueOf(metaInfo.getServicePort()));
        return metadata;
    }

    private ServiceMetaInfo convertInstanceToMeta(Instance instance) {
        ServiceMetaInfo metaInfo = new ServiceMetaInfo();
        String[] nameParts = instance.getServiceName().split(":");
        metaInfo.setServiceName(nameParts[0]);
        if (nameParts.length > 1) {
            metaInfo.setServiceVersion(nameParts[1]);
        }
        metaInfo.setServiceHost(instance.getIp());
        metaInfo.setServicePort(instance.getPort());
        return metaInfo;
    }
}